#[macro_export]
macro_rules! create_table {
    ($path:ident,$txn:ident,$builder:ident,$schema:ident) => {
        if !$path::Entity::find().one(&$txn).await.is_ok() {
            let stmt = $builder.build(&$schema.create_table_from_entity($path::Entity));
            $txn.execute(stmt).await?;
        }
    };
}

#[macro_export]
macro_rules! __gen_filter {
    ($sql:expr, $model:ident, $($col:ident:$method:ident:$value:expr$(=>$opt:ident)?)* , $col2:ident:$method2:ident:$value2:expr$(=>$opt2:ident)?) => {
        $crate::__gen_filter!($crate::__gen_filter!($sql, $model,$($col:$method:$value$(=>$opt)*)*),$model,$col2:$method2:$value2$(=>$opt2)*)
    };
    ($sql:expr, $model:ident, $col:ident:$method:ident:$value:expr) => {
        $sql.filter($model::Column::$col.$method($value))
    };
    ($sql:expr, $model:ident, $col:ident:$method:ident:$value:expr =>$opt:ident) => {
        $sql.apply_if($value, |sql, value| {
            sql.filter($model::Column::$col.$method(value))
        })
    };
    ($sql:expr, $model:ident,) => {
        $sql
    };
}

/// 生成Option类型
#[macro_export]
macro_rules! __opt_type{
    ($p_type:ident)=>{
        $p_type
    };
    ($p_type:ident,$opt:ident)=>{
        Option<$p_type>
    }
}

#[macro_export]
macro_rules! model_fetch {
    (
        #[model = $model:ident]
        #[filter = [$($f_col:ident:$f_m:ident:$f_v:expr),*]]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $(#[$m])*
        #[inline]
        $vis async fn $fn_name<T>(db: &DbConn, $($param:$crate::__opt_type!($p_type$(,$opt)*),)*) -> std::result::Result<Option<T>, sea_orm::DbErr>
        where
            T: PartialModelTrait + Send + Sync,
        {
            $crate::__gen_filter!($model::Entity::find(), $model, $($col:$p_m:$param $(=>$opt)*), *)
                $(.filter($model::Column::$f_col.$f_m($f_v)))*
                .into_partial_model()
                .one(db)
                .await
        }
    };
    (
        #[model = $model:ident]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $crate::model_fetch!{
            #[model = $model]
            #[filter = []]
            $(#[$m])*
            $vis fn $fn_name($($col:$p_m:$param:$p_type$(=>$opt)*),*)
        }
    };
}

#[macro_export]
macro_rules! model_list {
    (
        #[model = $model:ident]
        #[filter = [$($f_col:ident:$f_m:ident:$f_v:expr),*]]
        #[order = [$($order:ident:$order_dir:ident),*]]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $(#[$m])*
        $vis async fn $fn_name<T>(
            db: &DbConn,
            page: u64,
            page_size: u64,
            $($param:$crate::__opt_type!($p_type$(,$opt)*),)*
        ) -> std::result::Result<(u64, Vec<T>), sea_orm::DbErr>
        where
            T: PartialModelTrait + Send + Sync,
        {
            let sql = $crate::__gen_filter!($model::Entity::find(), $model , $($col:$p_m:$param $(=>$opt)*), *)
                $(.filter($model::Column::$f_col.$f_m($f_v)))*
                $(.order_by($model::Column::$order,sea_orm::Order::$order_dir))*
                .into_partial_model()
                .paginate(db, page_size);
            let total = sql.num_items().await?;
            let users = sql.fetch_page(page).await?;
            Ok((total, users))
        }
    };
    (
        #[model = $model:ident]
        #[filter = [$($f_col:ident:$f_m:ident:$f_v:expr),*]]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $crate::model_list!{
            #[model = $model]
            #[filter = [$($f_col:$f_m:$f_v),*]]
            #[order = []]
            $(#[$m])*
            $vis fn $fn_name($($col:$p_m:$param:$p_type$(=>$opt)*),*)
        }
    };
    (
        #[model = $model:ident]
        #[order = [$($order:ident:$order_dir:ident),*]]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $crate::model_list!{
            #[model = $model]
            #[filter = []]
            #[order = [$($order:$order_dir),*]]
            $(#[$m])*
            $vis fn $fn_name($($col:$p_m:$param:$p_type$(=>$opt)*),*)
        }
    };
    (
        #[model = $model:ident]
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident:$p_m:ident:$param:ident:$p_type:ident$(=>$opt:ident)?),*)
    ) => {
        $crate::model_list!{
            #[model = $model]
            #[filter = []]
            #[order = []]
            $(#[$m])*
            $vis fn $fn_name($($col:$p_m:$param:$p_type$(=>$opt)*),*)
        }
    }
}
